////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
//
//  Copyright (c) Microsoft Corporation. All rights reserved.
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <tinyclr_application.h>
#include <tinyhal.h>

////////////////////////////////////////////////////////////////////////////////
//#define MEMORY_CHECK
#ifdef MEMORY_CHECK

void memory_fill(unsigned long addr, char c, int len)
{
    int i;
    unsigned char *p = (unsigned char *)addr;
    for (i = 0; i < len; i++) {
        *p++ = (unsigned char)c;
    }
}

void memory_dump(unsigned long addr, int len)
{
    int i;
    unsigned char *p = (unsigned char *)addr;
    for (i = 0; i < len; i++) {
        if ((i & 0xf) == 0) {
            debug_printf("%08X ", (unsigned long)p);
        }
        debug_printf("%02X ", (unsigned char)(*p & 0xff));
        if ((i & 0xf) == 0xf) {
            debug_printf("\r\n");
        }
        p++;
    }
    debug_printf("\r\n");
}

void memory_fill_order_byte(unsigned long addr, int len)
{
    int i;
    unsigned char *p = (unsigned char *)addr;
    for (i = 0; i < len; i++) {
        *p++ = (unsigned char)(i & 0xff);
    }
}

int memory_compare_order_byte(unsigned long addr, int len, unsigned long *err_addr)
{
    int i;
    unsigned char *p = (unsigned char *)addr;
    for (i = 0; i < len; i++) {
        if (*p != (unsigned char)(i & 0xff)) {
            *err_addr = (unsigned long)p;
            return 0;
        }
        p++;
    }
    return 1;
}

int memory_check_order_byte(unsigned long addr, int len)
{
    unsigned long err_addr;
    memory_fill_order_byte(addr, len);
    if (!memory_compare_order_byte(addr, len, &err_addr)) {
        debug_printf("memory NG at %08x\r\n", err_addr);
        lcd_printf("memory NG at %08x\r\n", err_addr);
        memory_dump((err_addr & 0xffffff00), 256);
        return 0;
    }
    return 1;
}

void memory_fill_order_hword(unsigned long addr, int len)
{
    int i;
    unsigned short *p = (unsigned short *)addr;
    len >>= 1;
    for (i = 0; i < len; i++) {
        *p++ = (unsigned short)(i & 0xffff);
    }
}

int memory_compare_order_hword(unsigned long addr, int len, unsigned long *err_addr)
{
    int i;
    unsigned short *p = (unsigned short *)addr;
    len >>= 1;
    for (i = 0; i < len; i++) {
        if (*p != (unsigned short)(i & 0xffff)) {
            *err_addr = (unsigned long)p;
            return 0;
        }
        p++;
    }
    return 1;
}

int memory_check_order_hword(unsigned long addr, int len)
{
    unsigned long err_addr;
    memory_fill_order_hword(addr, len);
    if (!memory_compare_order_hword(addr, len, &err_addr)) {
        debug_printf("memory NG at %08x\r\n", err_addr);
        lcd_printf("memory NG at %08x\r\n", err_addr);
        memory_dump((err_addr & 0xffffff00), 256);
        return 0;
    }
    return 1;
}

void memory_fill_order_word(unsigned long addr, int len)
{
    int i;
    unsigned int *p = (unsigned int *)addr;
    len >>= 2;
    for (i = 0; i < len; i++) {
        *p++ = (unsigned int)(i & 0xffffffff);
    }
}

int memory_compare_order_word(unsigned long addr, int len, unsigned long *err_addr)
{
    int i;
    unsigned int *p = (unsigned int *)addr;
    len >>= 2;
    for (i = 0; i < len; i++) {
        if (*p != (unsigned int)(i & 0xffffffff)) {
            *err_addr = (unsigned long)p;
            return 0;
        }
        p++;
    }
    return 1;
}

int memory_check_order_word(unsigned long addr, int len)
{
    unsigned long err_addr;
    memory_fill_order_word(addr, len);
    if (!memory_compare_order_word(addr, len, &err_addr)) {
        debug_printf("memory NG at %08x\r\n", err_addr);
        lcd_printf("memory NG at %08x\r\n", err_addr);
        memory_dump((err_addr & 0xffffff00), 256);
        return 0;
    }
    return 1;
}
#define    EXRAM_START    0x60000000
#define    EXRAM_SIZE    0x80000
#define TEST_COUNT     10
void TestExRAM(void)
{
    int i;
    int flag = 1;
    memory_fill(EXRAM_START, 0, EXRAM_SIZE);
    for (i = 0; i < TEST_COUNT; i++) {
        //flag = memory_check_order_byte(EXRAM_START, EXRAM_SIZE);
        //flag &= memory_check_order_hword(EXRAM_START, EXRAM_SIZE);
        flag &= memory_check_order_word(EXRAM_START, EXRAM_SIZE);
        if (!flag)
            break;
        else {
            debug_printf("memory OK count %d\r", i);
            lcd_printf("memory OK count %d\r", i);
        }
    }
    if (flag)
        debug_printf("\r\n\memory OK\r\n");
    else {
        debug_printf("\r\n\memory NG\r\n");
        CPU_Halt();
    }
}
#endif
////////////////////////////////////////////////////////////////////////////////
void ApplicationEntryPoint()
{
    CLR_SETTINGS clrSettings;
#ifdef MEMORY_CHECK
//    TestExRAM();
#endif
    memset(&clrSettings, 0, sizeof(CLR_SETTINGS));

    clrSettings.MaxContextSwitches         = 50;
    clrSettings.WaitForDebugger            = false;
    clrSettings.EnterDebuggerLoopAfterExit = true;


    ClrStartup( clrSettings );

#if !defined(BUILD_RTM)
    debug_printf( "Exiting.\r\n" );
#else
    ::CPU_Reset();
#endif
}

BOOL Solution_GetReleaseInfo(MfReleaseInfo& releaseInfo)
{
    MfReleaseInfo::Init(releaseInfo,
                        VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD, VERSION_REVISION,
                        OEMSYSTEMINFOSTRING, hal_strlen_s(OEMSYSTEMINFOSTRING)
                        );
    return TRUE; // alternatively, return false if you didn't initialize the releaseInfo structure.
}

